#include "ThreadPool/LogMessage.hpp"
#include "ThreadPool/ThreadPool.hpp"

#include <iostream>
#include <string>
#include <memory>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>


 /*多线程用*/
// class ThreadData
// {
// public:
//     ThreadData(int sockFd, const std::string IP, uint16_t port)
//         : _sockFd(sockFd)
//         , _IP(IP)
//         , _port(port)
//     {}

// public:
//     int _sockFd;
//     std::string _IP;
//     uint16_t _port;
// };

class Server
{
private:
            /*后面再详谈listen第二个参数*/
    const int gBackLog = 20;

    // 客户端和服务端通信的接口
    static void service(int serverSock, const std::string& IP, uint16_t port, const std::string& name)
    {
        while(1)
        {
            // 直接用write和read通信
            char buff[1024];
            // read读取数据
            ssize_t readRes = read(serverSock, buff, sizeof(buff) - 1);
            if(readRes > 0)
            { // 返回值大于0，正常读取
                buff[readRes] = 0;
            }
            else if(readRes == 0)
            { // 返回值等于零，对端停止，这里服务端也停止
                LogMessage(NORMAL, _F, _L, "[%s:%d] =___cient disconnected___=", IP.c_str(), port);
                break;
            }
            else
            { // 返回值小于零，出错
                LogMessage(ERROR, _F, _L, "server read fail");
                break;
            }
            // 先打印一下谁发过来的数据
            LogMessage(NORMAL, _F, _L, "%s is servering\n\t   [%s:%d] send message ::%s", name.c_str(), IP.c_str(), port, buff);

            // echo服务器，接收到了之后，直接发回去
            ssize_t writeRes = write(serverSock, buff, strlen(buff));
            if(writeRes < 0)
            {
                LogMessage(ERROR, _F, _L, "server send fail");
            }
        }

        close(serverSock);
    }

    // // 客户端和服务端通信的接口
    // static void service(int serverSock, const std::string& IP, uint16_t port, const std::string& name)
    // {
    //     while(1)
    //     {
    //         // 直接用write和read通信
    //         char buff[1024];
    //         // read读取数据
    //         ssize_t readRes = read(serverSock, buff, sizeof(buff) - 1);
    //         if(readRes > 0)
    //         { // 返回值大于0，正常读取
    //             buff[readRes] = 0;
    //         }
    //         else if(readRes == 0)
    //         { // 返回值等于零，对端停止，这里服务端也停止
    //             LogMessage(NORMAL, _F, _L, "[%s:%d] =___cient disconnected___=", IP.c_str(), port);
    //             break;
    //         }
    //         else
    //         { // 返回值小于零，出错
    //             LogMessage(ERROR, _F, _L, "server read fail");
    //             break;
    //         }

    //         std::string tmp = buff;
    //         for(int i = 0; i < readRes; ++i)
    //         {
    //             if(buff[i] >= 'A' && buff[i] <= 'Z') buff[i] += 32;
    //         }
    //         // 先打印一下谁发过来的数据
    //         LogMessage(NORMAL, _F, _L, "%s is servering\n\t   [%s:%d] send message ::%s\t   [%s:%d] get message :: %s\n",\
    //                                          name.c_str(), IP.c_str(), port, tmp.c_str(), IP.c_str(), port, buff);

    //         // echo服务器，接收到了之后，直接发回去
    //         ssize_t writeRes = write(serverSock, buff, strlen(buff));
    //         if(writeRes < 0)
    //         {
    //             LogMessage(ERROR, _F, _L, "server send fail");
    //         }
    //     }

    //     close(serverSock);
    // }

        /*多线程用*/
    // static void* ThreadRoutine(void* args)
    // {
    //     pthread_detach(pthread_self());

    //     ThreadData* ptd = reinterpret_cast<ThreadData*>(args);
        
    //     int sockfd = ptd->_sockFd;
    //     std::string clientIP = ptd->_IP;
    //     uint16_t clientPort = ptd->_port;

    //     // 这里直接调用进行服务的函数就行
    //     service(sockfd, clientIP, clientPort);

    //     // delete掉ThreadData对象的空间，不然内存泄漏
    //     delete ptd;

    //     // 线程在执行完任务后，得关闭掉文件描述符，不然会文件描述符泄漏
    //     close(sockfd);
    // }
public:
    // 构造
    Server(uint16_t port, const std::string& IP = "", int sock = -1)
        : _port(port)
        , _IP(IP)
        , _listenSock(sock)
        , _pThreadPool(ThreadPool<Task>::GetThreadPoolPtr())
    {}

    // 初始化服务器
    void InitServer()
    {
        // 1. 创建套接字
             /*先AF_INET确定网络通信*/  /*这里用的是TCP，所以用SOCK_STREAM*/
        _listenSock = socket(AF_INET, SOCK_STREAM, 0);
        if(_listenSock == -1)
        {
            LogMessage(FATAL, _F, _L, "server create socket fail");
            exit(2);
        }
        LogMessage(DEBUG, _F, _L, "server create socket success, listen sock::%d", _listenSock);


        // 2. bind 绑定IP和port
        
        sockaddr_in local; // 各个字段填充
        memset(&local, 0, sizeof(local));
                                        // 若为空字符串就绑定当前主机所有IP
        local.sin_addr.s_addr = _IP == "" ? INADDR_ANY : inet_addr(_IP.c_str());
        local.sin_port = htons(_port);
        local.sin_family = AF_INET;
                                            /*填充好了绑定*/
        if(bind(_listenSock, reinterpret_cast<sockaddr*>(&local), sizeof(local)) < 0)
        {
            LogMessage(FATAL, _F, _L, "server bind IP+port fail");
            exit(3);
        }
        LogMessage(DEBUG, _F, _L, "server bind IP+port success");

        // 3. listen为套接字设置监听状态
        if(listen(_listenSock, gBackLog/*后面再详谈listen第二个参数*/) < 0)
        {
            LogMessage(FATAL, _F, _L, "srever listen fail");
            exit(4);
        }
        LogMessage(NORMAL, _F, _L, "server init success");
    }

             /***********************线程池版*****************************/
    // 启动服务器
    void StartServer()
    {
        _pThreadPool->RunAllThread(); // 启动线程池
        // 服务器就是个死循环，得一直跑
        while (1)
        {
            // 4.accept接收连接
                /*客户端相关字段*/
            sockaddr_in clientMessage;
            socklen_t clientLen = sizeof(clientMessage);
            memset(&clientMessage, 0, clientLen);
            // 接收连接
            int serverSock = accept(_listenSock, reinterpret_cast<sockaddr*>(&clientMessage), &clientLen);

            // 对端的IP和port信息
            std::string clientIP(inet_ntoa(clientMessage.sin_addr));
            uint16_t clientPort = ntohs(clientMessage.sin_port);

            if(serverSock < 0)
            {
                // 这里没连接上不能说直接退出，就像张三没有揽到某个客人餐馆就不干了，所以日志等级为ERROR
                LogMessage(ERROR, _F, _L, "server accept connection fail");
                continue; // 连接失败就接着找下一个客人进行连接
            }
            else
            {
                LogMessage(NORMAL, _F, _L, "server accept connection success ::[%s:%d] server sock::%d", \
                                                                    clientIP.c_str(), clientPort,serverSock);
            }

            // 往线程池中push任务
            _pThreadPool->PushTask(Task(service, serverSock, clientIP, clientPort));
        }
    }

    //          /***********************多线程版*****************************/
    // // 启动服务器
    // void StartServer()
    // {
    //     // 服务器就是个死循环，得一直跑
    //     while (1)
    //     {
    //         // 4.accept接收连接
    //             /*客户端相关字段*/
    //         sockaddr_in clientMessage;
    //         socklen_t clientLen = sizeof(clientMessage);
    //         memset(&clientMessage, 0, clientLen);
    //         // 接收连接
    //         int serverSock = accept(_listenSock, reinterpret_cast<sockaddr*>(&clientMessage), &clientLen);

    //         // 对端的IP和port信息
    //         std::string clientIP(inet_ntoa(clientMessage.sin_addr));
    //         uint16_t clientPort = ntohs(clientMessage.sin_port);

    //         if(serverSock < 0)
    //         {
    //             // 这里没连接上不能说直接退出，就像张三没有揽到某个客人餐馆就不干了，所以日志等级为ERROR
    //             LogMessage(ERROR, _F, _L, "server accept connection fail");
    //             continue; // 连接失败就接着找下一个客人进行连接
    //         }
    //         else
    //         {
    //             LogMessage(NORMAL, _F, _L, "server accept connection success ::[%s:%d] server sock::%d", \
    //                                                                 clientIP.c_str(), clientPort,serverSock);
    //         }

    //         // 接到数据后创建线程执行任务            
    //         pthread_t tid;
    //         ThreadData* ptd = new ThreadData(serverSock, clientIP, clientPort);
    //         pthread_create(&tid, nullptr, ThreadRoutine, reinterpret_cast<void*>(ptd)); 

    //         // 主线程走到这里时不需要进行通信，但是也不需要关掉serverfd，因为这个文件描述符和线
    //         // 程共享，关闭了就会导致创建出的线程无法和对方通信
    //     }
    // }

    //         /***********************多进程②版*****************************/
    // // 启动服务器
    // void StartServer()
    // {
    //     // 服务器就是个死循环，得一直跑
    //     while (1)
    //     {
    //         // 4.accept接收连接
    //             /*客户端相关字段*/
    //         sockaddr_in clientMessage;
    //         socklen_t clientLen = sizeof(clientMessage);
    //         memset(&clientMessage, 0, clientLen);
    //         // 接收连接
    //         int serverSock = accept(_listenSock, reinterpret_cast<sockaddr*>(&clientMessage), &clientLen);
    //         if(serverSock < 0)
    //         {
    //             // 这里没连接上不能说直接退出，就像张三没有揽到某个客人餐馆就不干了，所以日志等级为ERROR
    //             LogMessage(ERROR, _F, _L, "server accept connection fail");
    //             continue; // 连接失败就接着找下一个客人进行连接
    //         }
    //         else
    //         {
    //             LogMessage(NORMAL, _F, _L, "server accept connection success, server sock::%d", serverSock);
    //         }

    //         if(fork() == 0)
    //         { // 子进程
    //             // 子进程会继承父进程中的两个文件描述符，其中listenSock没有用，是让父进程用的，所以这里要关掉
    //             close(_listenSock);

    //             if(fork() > 0)
    //             { // 子进程
    //                 exit(0); // 子进程直接退出
    //             }

    //             // 孙进程进行通信，但子进程直接退出，孙进程就变成了孤儿进程，此时会直接被os接管
    //             std::string clientIP(inet_ntoa(clientMessage.sin_addr));
    //             uint16_t clientPort = ntohs(clientMessage.sin_port);
    //             service(serverSock, clientIP, clientPort);

    //             exit(0);
    //         }

    //         // 父进程此时直接等待子进程退出，非常顺畅，因为子进程刚生下来就没了，父进程直接就等到了，可以说这一步没有时间消耗
    //         waitpid(-1, nullptr, 0); 

    //         // 父进程走到这里时不需要进行通信，所以直接关掉serverSock
    //         close(serverSock);
    //     }
    // }

    //         /***********************多进程①版*****************************/
    // // 启动服务器
    // void StartServer()
    // {
    //     // 子进程退出后，直接忽略子进程发来的信号，子进程就会自动回收其资源，效率很高
    //     signal(SIGCHLD, SIG_IGN);
    //     // 服务器就是个死循环，得一直跑
    //     while (1)
    //     {
    //         // 4.accept接收连接
    //             /*客户端相关字段*/
    //         sockaddr_in clientMessage;
    //         socklen_t clientLen = sizeof(clientMessage);
    //         memset(&clientMessage, 0, clientLen);
    //         // 接收连接
    //         int serverSock = accept(_listenSock, reinterpret_cast<sockaddr*>(&clientMessage), &clientLen);
    //         if(serverSock < 0)
    //         {
    //             // 这里没连接上不能说直接退出，就像张三没有揽到某个客人餐馆就不干了，所以日志等级为ERROR
    //             LogMessage(ERROR, _F, _L, "server accept connection fail");
    //             continue; // 连接失败就接着找下一个客人进行连接
    //         }
    //         else
    //         {
    //             LogMessage(NORMAL, _F, _L, "server accept connection success, server sock::%d", serverSock);
    //         }

    //         if(fork() == 0)
    //         { // 子进程
    //             // 子进程会继承父进程中的两个文件描述符，其中listenSock没有用，是让父进程用的，所以这里要关掉
    //             close(_listenSock);

    //             // 连接成功了就让子进程通信
    //             std::string clientIP(inet_ntoa(clientMessage.sin_addr));
    //             uint16_t clientPort = ntohs(clientMessage.sin_port);
    //             service(serverSock, clientIP, clientPort);

    //             // 子进程退出后会变成僵尸进程，不处理会造成内存泄露，不过让父进程wait子进程的话很麻烦
    //             exit(0);                            /*|*/
    //         }                                       /*|*/
    //                                                 /*|*/
    //         // 父进程waitpid去阻塞式等待时这里和第一版的单线程没什么区别，因为父进程会卡在这里
    //         // 但是以非阻塞方式等待时又得每次到这都要执行一下waitpid或wait函数，很麻烦
    //         // 所以开头直接忽略子进程退出时的信号，子进程退出时就会自动回收其空间

    //         // 父进程走到这里时不需要进行通信，所以直接关掉serverSock
    //         close(serverSock);
    //     }
    // }

            /************************单线程版*********************************/
    // // 启动服务器
    // void StartServer()
    // {
    //     // 服务器就是个死循环，得一直跑
    //     while (1)
    //     {
    //         // 4.accept接收连接
    //             /*客户端相关字段*/
    //         sockaddr_in clientMessage;
    //         socklen_t clientLen = sizeof(clientMessage);
    //         memset(&clientMessage, 0, clientLen);
    //         // 接收连接
    //         int serverSock = accept(_listenSock, reinterpret_cast<sockaddr*>(&clientMessage), &clientLen);
    //         if(serverSock < 0)
    //         {
    //             // 这里没连接上不能说直接退出，就像张三没有揽到某个客人餐馆就不干了，所以日志等级为ERROR
    //             LogMessage(ERROR, _F, _L, "server accept connection fail");
    //             continue; // 连接失败就接着找下一个客人进行连接
    //         }
    //         else
    //         {
    //             LogMessage(NORMAL, _F, _L, "server accept connection success, server sock::%d", serverSock);
    //         }

    //         // 连接成功了就进行通信
    //         std::string clientIP(inet_ntoa(clientMessage.sin_addr));
    //         uint16_t clientPort = ntohs(clientMessage.sin_port);
    //         service(serverSock, clientIP, clientPort);

    //         // 一定要记得通信完了之后要关闭文件描述符，
    //         close(serverSock);
    //         // 若不关，后续通信的时候这个文件描述符会一直被占用，但是却已经没用了，这种行为也被称为文件描述符泄漏
    //         // 就像在客人吃完饭之后要收拾这个客人留下来的摊子，不然别的客人没法坐了
    //     }
    // }

    // 析构
    ~Server()
    {}

private:
    uint16_t _port; // 服务端端口号
    std::string _IP; // 服务端IP地址
    int _listenSock; // 初始套接字

    /*线程池*/
    std::unique_ptr<ThreadPool<Task>> _pThreadPool;
};